home *** CD-ROM | disk | FTP | other *** search
- Turbo Pascal for DOS Tutorial
- by Glenn Grotzinger
- Part 17: Primary Concepts of Pointers
- copyright(c) 1995-96 by Glenn Grotzinger
-
- Hello. Here is a solution from last time...
-
- program part16;
-
- var
- a: array[1..1000] of integer;
- number: integer;
- c, i, j, PIVOT, t: integer;
- found: boolean;
- location: integer;
- outfile: text;
-
- procedure quicksort(L, R: integer);
- { nothing to say we couldn't sort the data, especially with the
- fact that we will be performing 500 search hits on this 1000
- unit array...the overhead of sorting the data will be of good
- benefit in the long run... }
-
- begin
- if L < R then
- begin
- i := L + 1;
- j := R;
- PIVOT := A[L];
-
- repeat
- while a[i] <= PIVOT do inc(i);
- while a[j] > PIVOT do dec(j);
- if i < j then
- begin
- t := A[i];
- A[i] := a[j];
- A[j] := t;
- end;
- until i > j;
-
- a[l] := A[j];
- a[j] := PIVOT;
-
- quicksort(L, j-1);
- quicksort(i, R);
- end;
- end;
-
- procedure bsearch(number, lowend, highend: integer; var location: integer;
- var found: boolean);
- var
- midpoint: integer;
- begin
- if lowend > highend then
- found := false
- else
- begin
- midpoint := (lowend + highend) div 2;
- if number = a[midpoint] then
- begin
- found := true;
- location := midpoint;
- end
- else if number < a[midpoint] then
- bsearch(number, lowend, midpoint-1, location, found)
- else if number > a[midpoint] then
- bsearch(number, midpoint+1, highend, location, found);
- end;
- end;
-
- begin
- randomize;
- assign(outfile, 'LOCATION.TXT');
- rewrite(outfile);
-
- for c := 1 to 1000 do
- a[c] := random(10000) + 1;
-
- quicksort(1, 1000);
-
- for c := 1 to 500 do
- begin
- number := random(10000) + 1;
- bsearch(number, 1, 1000, location, found);
- if found then
- writeln(outfile, c, ') ', number, ' was found at position ',
- location, '.');
- end;
-
- close(outfile);
-
- end.
-
- Intro
- =====
- This will be the first of several parts on the use of pointers...This
- part will contain the basic idea behind pointers and their use. I
- would like feedback from anyone about how well they felt they learned
- from this tutorial, and the next two. They all will be about pointers,
- and I want to be sure I am doing OK in explaining them coherently. :>
-
- The Concept of a Pointer
- ========================
- A pointer is simply what it implies by the name. Something that points.
- A pointer is a 4 byte double word that stores the segment and offset in
- memory where the variable is located.
-
- We have referred to before a method of getting more than 64K in a data
- structure, in the array section. This is a way. A pointer is placed on
- what is referred to as the heap. The heap is the remainder of conventional
- memory not used by the program itself, the data stack, or any TSRs that
- may be on the system at any one time. The data stack is where variables
- are normally allocated directly by name and can be a maximum of 64K in size.
-
- Why would we want to use pointers? Well, we have already eluded to one
- reason, to get around the 64K data limit. Another reason is to dynamically
- allocate memory space. Basically, any variables declared by name(s) in a
- program is allocated at the initial start-up of a program, and is allocated
- until the end of the program. For a lengthy program with a lot of variables,
- we may not want all variables to be allocated for something at the start.
- Therefore, we can, with pointers, allocate and deallocate memory anytime
- we wish in a program.
-
- If we want to save memory in the data stack, 1 4-byte pointer compared to,
- say, an array of 1000 integers would be preferable. That is one function
- of a pointer.
-
- In using pointers, we must remember that they are not direct variables,
- but addresses of variables. Let us look at the first example program
- below to see exactly what I mean by the last statement. We also will
- see how to properly create variable space address pointers in memory,
- address that variable space, and then deallocate it.
-
- program pointers_one;
-
- type
- strptr = ^string;
- var
- a, b, c: strptr;
-
- begin
- new(a);
- a^ := 'Turbo Pascal';
- new(b);
- b^ := 'is fun!!!!!!';
-
- writeln('a is now "', a^, '".');
- writeln('b is now "', b^, '".');
-
- new(c);
- c^ := a^;
- a^ := b^;
- b^ := c^;
- dispose(c);
-
- writeln;
- writeln('a is now "', a^, '".');
- writeln('b is now "', b^, '".');
- dispose(a);dispose(b);
-
- end.
-
- We see the use of several use conventions in the program above. We have
- three pointers listed to be pointers of strings. (as a note, any data
- type that will eventually be a pointer should NORMALLY be defined under
- the type declaration to facilitate the use of pointers in procedures.
- We will see this later.)
-
- In the declaration to allocate the pointers, we used the ^ sign first, then
- the datatype. We say that the pointer will eventually point to a string
- variable.
-
- To address each of the pointer variables, we used the ^ sign after the
- particular variable name. The ^ sign references the variable that the
- pointer is pointing to, and NOT the pointer itself. You may see this
- by doing a debug trace for a, b, and c on that program. You will
- clearly see that the pointer's contents is NOT what the variable's
- contents is...
-
- The next thing to note is the assignment statements. For a pointer
- variable, we are not assigning direct values, but MOVING THE POINTER
- address. When we say a^ := c^, we are moving the pointer c to point
- to the value that a points to. **WE ARE NOT DIRECTLY CHANGING THE
- VALUE OF THAT LOCATION IN MEMORY!!!**.
-
- The last thing to note is the strategically placed uses of the functions
- new() and dispose(). These are new functions to us that we will learn
- and make use of in the system unit. The new() function will allocate
- the space for the pointer listed in the variable on the heap. The
- dispose() function will deallocate the space for the pointer on the heap.
- As you can see, we created and removed the variables as we needed them.
-
- The next thing you were probably wondering with pointers is how to get
- a pointer to not point to anything. Make it address a reserved word
- called nil. If I want pointer p to not point to anything, then I would
- write:
-
- p := nil;
-
- Whatever you do, do not set a pointer to nil before you dispose of the
- pointer. The system will lose track of the variable on the heap, and
- therefore is LOST to the system. Keep this issue in mind as we do
- our work and examples with pointers.
-
- Look up getmem() and freemem().
-
- Another issue that wasn't covered above is how we determine how much
- memory is in the heap. Use the functions memavail and maxavail for
- the purpose of finding out how much memory you can allocate and if the
- pointer data structure is big enough, BE SURE TO CHECK AND SEE IF YOU
- HAVE THE MEMORY TO ALLOCATE before you allocate it for a big structure.
-
- Procedure or Function Pointers
- ==============================
- A procedure or function may also be addressed as a pointer. For that,
- as you will see in the example, we can use a declaration for a variable
- exactly like the procedure or function declaration. It is very useful
- to minimize code usage, and make things multi-functional. This sheds
- some light into the inner workings of the write command, as was wondered
- in c.l.p.b. a little while ago...
-
- program pointer_two;
- type
- compfunc = function(a, b: integer):integer;
- var
- compute: compfunc;
- first, second: integer;
- choice: char;
-
- {$F+}
- function compadd(a, b: integer): integer;
- begin
- compadd := a + b;
- end;
- function compsub(a, b: integer): integer;
- begin
- compsub := a - b;
- end;
- function compmult(a, b: integer): integer;
- begin
- compmult := a * b;
- end;
- function compdiv(a, b: integer): integer;
- begin
- compdiv := a div b;
- end;
-
- {$F-}
-
- begin
- @compute := nil;
- write('Enter a first number: ');
- readln(first);
- write('Enter a second number: ');
- readln(second);
- write('Enter +, -, *, or / as a operation: ');
- readln(choice);
- case choice of
- '+': compute := compadd;
- '-': compute := compsub;
- '*': compute := compmult;
- '/': compute := compdiv;
- else
- writeln('Enter a correct option.');
- end;
- compute(first, second);
- writeln(first, ' ', choice, ' ',second,' = ',compute(first, second));
-
- end.
- As you can see, we are assigning a particular function to the function
- named compute. After that, compute performs the specified function of
- the function that we just assigned to it. The rule is that those FAR
- declarations MUST be present. As well, you can see how to refer to the
- procedure pointer (as @procedure). As long as the declarations are
- similar for all the functions, we can readdress functions/procedures
- using a variable like we did above.
-
- We see that we can probably cut down on a lot of code by using this
- method if we had several different ways of doing things, with large
- amounts of code for each thing. For example, if we wanted to sort
- something based on user input dependent upon many different methods
- or types (say sort increasing by name, decreasing by name, increasing
- on size, by date, et.al), we can set up our swapping procedure to be
- the way the compute procedure is above.
-
- Now, we will lead into a special usage of a pointered procedure called
- exitproc.
-
- ExitProc
- ========
- This is a special defined procedure pointer in Pascal that will determine
- the procedures that will be performed upon an exit, NO MATTER what happens,
- EVEN IF THERE IS A RUN-TIME ERROR. Here is your method on being able to
- catch and log those run-time errors either to the screen, or to an errors
- log. The primary usage of an exit procedure, though, is to perform any
- maintenance that needs to be done upon termination that may not get done
- upon an abnormal termination, such as closing files. The way things work
- are basically the same as above...
-
- Here is a short example...I will force a run-time error in this program,
- so we can see that the end gets run anyway. As you may see, exitproc
- is defined as a pointered procedure when we work with it. The rest is
- basically documented.
-
- program pointer_three;
-
- var
- exitsave: procedure;
- afile: text;
-
- {$F+} { must be far }
- procedure myexit; {must be parameterless}
- begin
- if exitcode <> 0 then
- writeln('There was a problem.');
- writeln('We are exiting...');
- end;
- {$F-}
-
- begin
- @exitsave := exitproc; { saving the original exit procedure }
- exitproc := @myexit; { set to new exit procedure }
-
- { I am placing a couple of error situations in here so you can
- experiment with what is going on...try it without errors too! }
-
- {1 - here is a standard file not found RTE.}
- assign(afile, '()()()().!!!');
- reset(afile);
-
- {2 - here is a division by zero.}
- { writeln(3 / 0); }
-
- exitproc := @exitsave; { set the original exit procedure back }
- end.
-
- Here is enough material that I believe that is enough to digest for right
- now on use of pointers. Practice allocating and using pointers very
- heavily, as we will get into more advanced issues of using pointers in the
- next two parts...Remember that ANY structure can be placed as a pointer,
- except for files, and remember to define types for all pointers.
-
- Practice Programming Problem #17
- ================================
- Randomly generate 15000 numbers from 1-25000 into an array.
- Then generate another 10000 numbers from 1-25000.
- If there is a number from the second set of numbers that happens to be in
- the first set of numbers, write out to the file named LOCAT2.TXT something
- such as:
-
- 13131 was found at position 12000.
-
- Only indicate the first instance of the number you encounter.
- You may wish to write a "redrawing bar" for a process indicator.
-
- Note: Be sure with the allocation for those first 15000 numbers that you
- keep in line with the topic of this tutorial.
-
- Next Time
- =========
- We will cover the concept of linked lists, or chained lists. Practice
- very heavily the idea of pointers, because you will need use of them
- again in the next section. E-mail ggrotz@2sprint.net with your comments.
-
-
-